package com.imooc.socialecom.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.imooc.socialecom.helper.RedisOperation;
import com.imooc.socialecom.mapper.ItemMapper;
import com.imooc.socialecom.pojo.Item;
import com.imooc.socialecom.pojo.Sku;
import com.imooc.socialecom.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author socialecom
 * @since 2024-09-24
 */
@Service
@Slf4j
public class ItemServiceImpl extends ServiceImpl<ItemMapper, Item> implements ItemService, InitializingBean {

    @Autowired
    private SkuService skuService;

    @Autowired
    private SkuAttributeInfoService skuAttributeInfoService;

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SellerService sellerService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisOperation redisOperation;

    private RestHighLevelClient client = null;

    @Override
    @Transactional
    public Sku createSku(Sku sku) {
        skuService.save(sku);
        sku.getSkuAttributeInfoList().forEach(skuAttributeInfo -> {
            skuAttributeInfo.setSkuId(sku.getId());
            skuAttributeInfoService.save(skuAttributeInfo);
        });

        return sku;
    }

    @Override
    @DS("slave1")
    public Item getItem(Long id, Long shopId) {

        Item item = null;
        String itemRedisKey = "itemId_" + id;
        String skuRedisKey = "itemId_" + id + "_skuList_shopId_" + shopId;

        item = (Item) redisTemplate.opsForValue().get(itemRedisKey);
        log.info("读取Redis item缓存 ------ 成功");

        if (ObjectUtil.isNull(item)) {
            log.info("读取Redis item缓存 ------ 失败");
            item = getById(id);
            if (ObjectUtil.isNull(item)) {
                // 防止缓存穿透
                item = new Item();
                redisOperation.asyncRedisStringSet(itemRedisKey, item);
                return item;
            }
            item.setSellerName(sellerService.getById(item.getSellerId()).getSellerName());
            item.setBrand(brandService.getById(item.getBrandId()).getName());
            item.setCategory(categoryService.getById(item.getCategoryId()).getName());
            redisOperation.asyncRedisStringSet(itemRedisKey, item);
        }

        List<Sku> skuList = (List<Sku>) redisTemplate.opsForValue().get(skuRedisKey);
        log.info("读取Redis skuList缓存 ------ 成功");
        if (CollUtil.isEmpty(skuList)) {
            log.info("读取Redis skuList缓存 ------ 失败");
            QueryWrapper<Sku> skuQueryWrapper = new QueryWrapper<>();
            skuQueryWrapper.eq("item_id", item.getId());
            skuList = skuService.listByShopId(skuQueryWrapper, shopId);
            if (CollUtil.isEmpty(skuList)) {
                // 防止缓存穿透
                Sku sku = new Sku();
                sku.setId(-1L);
                skuList.add(sku);
                item.setSkuList(skuList);
                redisOperation.asyncRedisStringSet(skuRedisKey, skuList);
                return item;
            }
            redisOperation.asyncRedisStringSet(skuRedisKey, skuList);
        }
        item.setSkuList(skuList);

        return item;
    }

    @Override
    public List<Item> search(String name, Long shopId) throws IOException {

        SearchRequest searchRequest = new SearchRequest("item");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchRequest.source(searchSourceBuilder);
        QueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", name);
        searchSourceBuilder.query(matchQueryBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        List<Object> itemIdList = Arrays.stream(searchResponse.getHits().getHits()).map(hit -> hit.getId()).collect(Collectors.toList());
        List<Item> itemList = itemIdList.stream().map(obj -> {
            return getItem(new Long((String) obj), shopId);
        }).collect(Collectors.toList());
        return itemList;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        client = new RestHighLevelClient(RestClient.builder(new HttpHost("localhost", 9200, "http")));
    }
}
